﻿import math
from collections import namedtuple

def color_huetorgb(m1, m2, h):
	if h < 0:
		h += 1
	elif h > 1:
		h -= 1
		
	if h*6 < 1:
		return m1 + (m2-m1) * h * 6
	elif h*2 < 1:
		return m2
	elif h*3 < 2:
		return m1 + (m2-m1) * (2.0/3.0 - h) * 6
	else:
		return m1

	
class Color(namedtuple('tupleRGB', 'r g b')):
	"""Color用以表示顏色
	>>> Color(10,10,10) + Color(-5,10,250)
	Color(5, 20, 260)
	
	>>> (Color(10,10,10) + Color(-5,10,250)).normalize()
	Color(5, 20, 255)
	
	>>> Color(255,0,30).b
	30
	
	>>> Color(255,0,30).rf
	1.0
	
	>>> Color(255,0,30).gf
	0.0
	
	"""
	
	__slots__ = ()
	
	def __add__(self, op):
		return Color(self.r+op.r, self.g+op.g, self.b+op.b)
		
	def __sub__(self, op):
		return Color(self.r-op.r, self.g-op.g, self.b-op.b)
		
		
	def __mul__(self, op):
		return Color(self.r * op, self.g * op, self.b * op)
		
	def __floordiv__(self, op):
		return Color(self.r // op, self.g // op, self.b // op)
		
	def __truediv__(self, op):
		return Color(self.r / op, self.g / op, self.b / op)
		
	#def __rmul__(self, op):
	#	return Color(self.r * op, self.g * op, self.b * op)
		
	#def __floordiv__(self, op):
	#	return Color(self.r // op, self.g // op, self.b // op)
		
	#def __rtruediv__(self, op):
	#	return Color(self.r / op, self.g / op, self.b / op)
	
	def __str__(self):
		return "[r = %r, g = %r, b = %r]" % (self.r, self.g, self.b)
		
	def __repr__(self):
		return "Color(%r, %r, %r)" % (self.r, self.g, self.b)
	
	__rmul__ = __mul__
	__rfloordiv__ = __floordiv__
	__rtruediv__ = __truediv__
	
	def normalize(self):
		"""
		>>> HSV(0.0002,1,0.5).normalize() == Color(255,0,0)
		True
		"""
		r = max(min(int(self.r), 255), 0)
		g = max(min(int(self.g), 255), 0)
		b = max(min(int(self.b), 255), 0)
		return Color(r, g, b)
		
	def setHSV(self, h=None, s=None, v=None):
		if h == None:
			h = self.h
		if s == None:
			s = self.s
		if v == None:
			v = self.v
		
		if s == 0:
			r = g = b = v * 255
		else:
			if v <= 0.5:
				m2 = v * (1.0 + s)
			else:
				m2 = v + s - v*s
			m1 = 2.0 * v - m2
			r = color_huetorgb(m1, m2, h + 1.0/3.0) * 255
			g = color_huetorgb(m1, m2, h) * 255
			b = color_huetorgb(m1, m2, h - 1.0/3.0) * 255
		return Color(r,g,b)
		
	def toHSV(self):
		_max = max(max(self.rf, self.gf), self.bf)
		_min = min(min(self.rf, self.gf), self.bf)
		delta = (_max - _min)
		v = (_max + _min) / 2.0
		
		if (_max == _min):
			return (0, 0, v)
		
		if (v < 0.5):
			s = delta / (_max + _min)
		else:
			s = delta / (2.0 - _max - _min)
		
		if (self.rf == _max):
			h = (self.gf - self.bf) / delta;
		elif (self.gf == _max):
			h = 2.0 + (self.bf - self.rf) / delta;
		else:
			h = 4.0 + (self.rf - self.gf) / delta;
	 
		h /= 6.0; 
	 
		if (h < 0.0):
			h += 1.0
		
		return (h, s, v)
		
	def _get_rf(self):
		return self.r / 255.0
	def _get_gf(self):
		return self.g / 255.0
	def _get_bf(self):
		return self.b / 255.0
	
	rf = property(_get_rf)
	gf = property(_get_gf)
	bf = property(_get_bf)
	
	def _get_h(self):
		return self.toHSV()[0]
	def _get_s(self):
		return self.toHSV()[1]
	def _get_v(self):
		return self.toHSV()[2]

	h = property(_get_h)
	s = property(_get_s)
	v = property(_get_v)
		
def HSV(h,s,v):
	"""
	>>> HSV(0,1,0.5) == Color(255,0,0)
	True
	"""
	return Color(0,0,0).setHSV(h,s,v)

def RGB(r,g,b):
	"""
	>>> RGB(100,10,1) == Color(100,10,1)
	True
	"""
	return Color(r,g,b)
			
class Point(namedtuple('tuplePoint', 'x y')):
	"""一個類別用以敘述二維座標中的「點」。
		
		對於「點」的描述，有兩種方法讓我難以取捨，以兩點相加為例：
		
		1. 
		   使用數組(x, y)  ---  (p1[0] + p2[0], p1[1] + p2[1])
		   
		2.
		   使用物件Point --- p1 + p2
		   
		數組在各方面都比物件Point快5~10倍，
		不過物件Point在易讀性上大勝數組，我想這是比較好的選擇。
		
		物件Point內建四則運算、比較、捨入。
		四則運算：
		
		>>> Point(10,10) + Point(-5,3)
		Point(5, 13)
		>>> Point(10,10) - Point(-5,3)
		Point(15, 7)
		>>> Point(10,10) * 3
		Point(30, 30)
		>>> Point(12,9) / -10.0
		Point(-1.2, -0.9)
		>>> Point(12,9) // -10
		Point(-2, -1)
		>>> -Point(10,10)
		Point(-10, -10)
		
		運算子是有交換律的：
		
		>>> 3 * Point(10,10)
		Point(30, 30)
		
		比較相等與比較不相等：
		
		>>> Point(5,13) == Point(5,13)
		True
		>>> Point(5,13) != Point(5,-13)
		True
		
		捨入到小數點後第一位：
		
		>>> round(Point(21.87,12.34),1)
		Point(21.9, 12.3)
	
		自運算
		>>> p = Point(10,10)
		>>> p += Point(-5,3)
		>>> p
		Point(5, 13)
		>>> del p
		
		.. image:: test128x128_32_1.bmp
		
		.. code-block:: python
		   :linenos:
		   
		   def __add__(self, op):
		      p = Point()
		      p.x = self.x + op.x
		      p.y = self.y + op.y
		      return p
		
	"""
	__slots__ = ()
	
	def __add__(self, op):
		return Point(self.x + op.x, self.y + op.y)
		
	def __sub__(self, op):
		return Point(self.x - op.x, self.y - op.y)
		
	def __mul__(self, op):
		return Point(self.x * op, self.y * op)
		
	def __floordiv__(self, op):
		return Point(self.x // op, self.y // op)
		
	def __truediv__(self, op):
		return Point(self.x / op, self.y / op)
		
	#def __rmul__(self, op):
	#	return Point(self.x * op, self.y * op)
		
	#def __rfloordiv__(self, op):
	#	return Point(self.x // op, self.y // op)
		
	#def __rtruediv__(self, op):
	#	return Point(self.x / op, self.y / op)
	
	__rmul__ = __mul__
	__rfloordiv__ = __floordiv__
	__rtruediv__ = __truediv__
	
	def __neg__(self):
		return Point(-self.x, -self.y)
		
	def __round__(self, n=0):
		return Point(round(self.x, n), round(self.y, n))
	
	#def __eq__(self, op):
	#	return self.x == op.x and self.y == op.y
		
	def __str__(self):
		return "[x = %r, y = %r]" % (self.x, self.y)
		
	def __repr__(self):
		return "Point(%r, %r)" % (self.x, self.y)
	
	'''
	def MoveTo(self, p):
		"""移動到新的點(``Point``) *p*"""
		self.x = p.x
		self.y = p.y
		
	def Pos(self):
		"""傳回點所在的點，對於 ``Point`` 來說也就是傳回自己。"""
		return self
	'''
	
class Vector(Point):
	"""Vector用以表示方向向量
	>>> Vector(10, 20)
	Vector(10, 20)
	
	>>> Vector(6, 8).length
	10.0
	
	>>> Vector(6, 8).unit
	Vector(0.6, 0.8)
	
	>>> round(Vector(1, 1.7320508075688772935274463415059).angle, 2)
	60.0
	>>> round(Vector(-1, 1.7320508075688772935274463415059).angle, 2)
	120.0
	>>> round(Vector(-1, -1.7320508075688772935274463415059).angle, 2)
	240.0
	>>> round(Vector(1, -1.7320508075688772935274463415059).angle, 2)
	300.0
	
	>>> Vector(3, 2) + Vector(2, -2)
	Vector(5, 0)
	
	"""
	
	# ---- 這個部分完全跟Point一樣 ----
	__slots__ = ()
	def __add__(self, op):
		return Vector(self.x + op.x, self.y + op.y)
		
	def __sub__(self, op):
		return Vector(self.x - op.x, self.y - op.y)
		
	def __mul__(self, op):
		return Vector(self.x * op, self.y * op)
		
	def __floordiv__(self, op):
		return Vector(self.x // op, self.y // op)
		
	def __truediv__(self, op):
		return Vector(self.x / op, self.y / op)
		
	__rmul__ = __mul__
	__rfloordiv__ = __floordiv__
	__rtruediv__ = __truediv__
	
	def __neg__(self):
		return Vector(-self.x, -self.y)
		
	def __round__(self, n=0):
		return Vector(round(self.x, n), round(self.y, n))
	# ----------------------------------
	
	def __str__(self):
		return "[x = %r, y = %r]" % (self.x, self.y)
		
	def __repr__(self):
		return "Vector(%r, %r)" % (self.x, self.y)
		
	def _get_length(self):
		return (self.x * self.x + self.y * self.y) ** 0.5
	
	def _get_unit(self):
		return Vector(self.x / self.length, self.y / self.length)
		
	def _get_angle(self):
		d = math.degrees(math.atan2(self.y, self.x))
		if d < 0:
			return d + 360
		else:
			return d
		
		
	length = property(_get_length)
	unit = property(_get_unit)
	angle = property(_get_angle)
	

class Size(namedtuple('tupleSize', 'w h')):
	"""
	>>> Size(10, 20)
	Size(10, 20)
	"""
	def __add__(self, op):
		return Size(self.w + op.w, self.h + op.h)
		
	def __sub__(self, op):
		return Size(self.w - op.w, self.h - op.h)
		
	def __mul__(self, op):
		if isinstance(op, int) or isinstance(op, float):
			return Size(self.w * op, self.h * op)
		elif isinstance(op, Size):
			return Size(self.w * op.w, self.h * op.h)
		
	def __floordiv__(self, op):
		if isinstance(op, int) or isinstance(op, float):
			return Size(self.w // op, self.h // op)
		elif isinstance(op, Size):
			return Size(self.w // op.w, self.h // op.h)
		
	def __truediv__(self, op):
		if isinstance(op, int) or isinstance(op, float):
			return Size(self.w / op, self.h / op)
		elif isinstance(op, Size):
			return Size(self.w / op.w, self.h / op.h)
		
	__rmul__ = __mul__
	__rfloordiv__ = __floordiv__
	__rtruediv__ = __truediv__
		
	def __str__(self):
		return "[w = %r, h = %r]" % (self.w, self.h)
		
	def __repr__(self):
		return "Size(%r, %r)" % (self.w, self.h)
	
	
class Rect(namedtuple('tupleRect', 'x y w h')):
	"""一個類別用以敘述矩形邊界。
	>>> Rect(5, 10, 8, 8)
	Rect(5, 10, 8, 8)
	>>> Rect(0, 0, 10, 10).setpos(Point(5, 5)).setsize((20,20))
	Rect(5, 5, 20, 20)
	>>> Rect(10, 10, -10, -10).normalize()
	Rect(0, 0, 10, 10)
	>>> Rect(10, 10, -10, -10) == Rect(0, 0, 10, 10)
	True
	>>> Rect(10, 10, -10, -10).size
	Size(10, 10)
	
	>>> Rect(10, 10, -10, -10).center
	Point(5, 5)
	>>> Rect(10, 10, -10, -10).bottomright
	Point(10, 10)
	
	"""
	#__slots__ = ["x", "y", "width", "height"]
	__slots__ = ()
	
	def normalize(self):
		if self.w < 0:
			x = self.x + self.w
			w = -self.w
		else:
			x = self.x
			w = self.w
			
		if self.h < 0:
			y = self.y + self.h
			h = -self.h
		else:
			y = self.y
			h = self.h
			
		return Rect(x, y, w, h)


	def qtree(self, dir):
		if dir == 0:
			return Rect(self.top, self.left, self.w/2, self.h/2)
		if dir == 1:
			return Rect(self.top, self._get_centery(), self.w/2, self.h/2)
		if dir == 2:
			return Rect(self._get_centerx(), self.left, self.w/2, self.h/2)
		if dir == 3:
			return Rect(self._get_centerx(), self._get_centery(), self.w/2, self.h/2)
		else:
			pass
			
	def __str__(self):
		return "[x = %r, y = %r, w = %r, h = %r]" % (self.x, self.y, self.w, self.h)
		
	def __repr__(self):
		return "Rect(%r, %r, %r, %r)" % (self.x, self.y, self.w, self.h)
		
		
	def __round__(self, n=0):
		return Rect(round(self.x, n), round(self.y, n), round(self.w, n), round(self.h, n))
	
	def __eq__(self, op):
		nop = op.normalize()
		self = self.normalize()
		return nop.x == self.x and nop.y == self.y and nop.w == self.w and nop.h == self.h

		
	def setpos(self, point):
		return Rect(point[0], point[1], self.w, self.h)
		
	def setsize(self, size):
		return Rect(self.x, self.y, size[0], size[1])
		
	def union(self, rect):
		pass
	def intersection(self, rect):
		pass
	
	def _get_top(self):
		return self.normalize().y
	def _get_left(self):
		return self.normalize().x
	def _get_bottom(self):
		return self.normalize().y + self.normalize().h
	def _get_right(self):
		return self.normalize().x + self.normalize().w
	
	def _get_centerx(self):
		centerx = self.normalize().x + self.normalize().w / 2
		if centerx % 1 == 0:
			return int(centerx)
		else:
			return centerx
			
	def _get_centery(self):
		centery = self.normalize().y + self.normalize().h / 2
		if centery % 1 == 0:
			return int(centery)
		else:
			return centery
			
	def _get_topleft(self):
		return Point(self.top, self.left)
	def _get_bottomleft(self):
		return Point(self.bottom, self.left)
	def _get_topright(self):
		return Point(self.top, self.right)
	def _get_bottomright(self):
		return Point(self.bottom, self.right)
		
	def _get_midtop(self):
		return Point(self.top, self._get_centery())
	def _get_midleft(self):
		return Point(self._get_centerx(), self.left)
	def _get_midbottom(self):
		return Point(self.bottom, self._get_centery())
	def _get_midright(self):
		return Point(self._get_centerx(), self.right)
		
	def _get_center(self):
		return Point(self._get_centerx(), self._get_centery())
	
	def _get_size(self):
		n = self.normalize()
		return Size(n.w, n.h)
		
	top = property(_get_top)
	left = property(_get_left)
	bottom = property(_get_bottom)
	right = property(_get_right)
	
	topleft = property(_get_topleft)
	bottomleft = property(_get_bottomleft)
	topright = property(_get_topright)
	bottomright = property(_get_bottomright)
	
	midtop = property(_get_midtop)
	midleft = property(_get_midleft)
	midbottom = property(_get_midbottom)
	midright = property(_get_midright)
	
	center = property(_get_center)
	size = property(_get_size)


	
def moveto(rect, point):
	"""
	>>> moveto(Rect(5,5,5,5), Point(10,10))
	Rect(10, 10, 5, 5)
	"""
	return Rect(point.x, point.y, rect.w, rect.h)
	
# 有bug
'''
def RectAttach(rect, point_inside, point):
	"""以一個矩形中的點為基準點，將基準點貼住外點，這會造成整個矩形的移動。
	>>> RectAttach(Rect(5, 5, 5, 5), Point(2, 2), Point(1, 1))
	Rect(4, 4, 5, 5)
	"""
	return Rect(point.x - point_inside.x, point.y - point_inside.y, rect.w, rect.h)
'''
	
def RectBy2Point(p1, p2):
	"""從兩個點建立一個矩形。
	>>> RectBy2Point(Point(5, 10), Point(10, 5))
	Rect(5, 5, 5, 5)
	"""
	bx = max(p1.x, p2.x)
	sx = min(p1.x, p2.x)
	by = max(p1.y, p2.y)
	sy = min(p1.y, p2.y)
	return Rect(sx, sy, bx - sx, by - sy)
	
def RectByPointSize(p, size):
	"""用一個左上角點和一個尺寸來建立一個矩形。
	>>> RectByPointSize(Point(5, 5), Size(5, 5))
	Rect(5, 5, 5, 5)
	"""
	return Rect(p.x, p.y, size.w, size.h)
	

H_ROUT = frozenset((3, 7))
H_LOUT = frozenset((0, 2))
H_IN = frozenset((1, 6))
H_INC = frozenset((0, 7))
H_RINS = frozenset((2, 7))
H_LINS = frozenset((0, 5))

V_ROUT = frozenset((3+8, 7+8))
V_LOUT = frozenset((0+8, 2+8))
V_IN = frozenset((1+8, 6+8))
V_INC = frozenset((0+8, 7+8))
V_RINS = frozenset((2+8, 7+8))
V_LINS = frozenset((0+8, 5+8))


def CommonCollided(rect_static, rect_opposite):
	"""通用的碰撞檢測方式，可以取得碰撞的方向。
	可以檢測出6*6+6+6=48種狀態
	>>> (H_RINS | V_RINS) <= CommonCollided(Rect(0,0,5,5), Rect(4,4,5,5))
	True
	>>> (H_INC | V_INC) <= CommonCollided(Rect(0,0,5,5), Rect(-1,-1,10,10))
	True
	"""

	collidelist = []
	if rect_static.left > rect_opposite.left:
		collidelist.append(0)
	if rect_static.left < rect_opposite.left:
		collidelist.append(1)
	if rect_static.right > rect_opposite.left:
		collidelist.append(2)
	if rect_static.right < rect_opposite.left:
		collidelist.append(3)
	#if rect_static.left > rect_opposite.right:
	#	collidelist.append(4)
	if rect_static.left < rect_opposite.right:
		collidelist.append(5)
	#if rect_static.right > rect_opposite.right:
	#	collidelist.append(6)
	if rect_static.right < rect_opposite.right:
		collidelist.append(7)
	
	
	if rect_static.top > rect_opposite.top:
		collidelist.append(8)
	if rect_static.top < rect_opposite.top:
		collidelist.append(9)
	if rect_static.bottom > rect_opposite.top:
		collidelist.append(10)
	if rect_static.bottom < rect_opposite.top:
		collidelist.append(11)
	#if rect_static.top > rect_opposite.bottom:
	#	collidelist.append(12)
	if rect_static.top < rect_opposite.bottom:
		collidelist.append(13)
	#if rect_static.bottom > rect_opposite.bottom:
	#	collidelist.append(14)
	if rect_static.bottom < rect_opposite.bottom:
		collidelist.append(15)
		
	return frozenset(collidelist)
	
	
	
def FastCollided(rect1, rect2):
	"""檢測兩矩形是否碰撞。
	>>> FastCollided(Rect(0,0,5,5), Rect(4,4,5,5))
	True
	>>> FastCollided(Rect(0,0,5,5), Rect(6,6,5,5))
	False
	"""
	if ((rect1.left > rect2.right) or (rect1.right < rect2.left)) and \
	   ((rect1.top > rect2.bottom) or (rect1.bottom < rect2.top)):
		return False
	else:
		return True
		
'''
class RotatedRect():
	def __init__(self):
		self.bounding = Rect()
		self.inside = Rect()
		self.rotate = 0
'''

def Distance(p1, p2):
	"""計算任意兩點之間的距離。
	>>> int(Distance(Point(10, 10), Point(13, 14)))
	5
	>>> int(Distance(Point(-3, 4), Point(0, 0)))
	5
	"""
	
	return math.sqrt((p2.x - p1.x)**2 + (p2.y - p1.y)**2)

# rotate by original
def PointRotate(p, angle, o=Point(0,0)):
	"""以點 *o* 為中心將點 *p* 順時針旋轉 *angle* 度，
	此函數回傳旋轉後的新點。
	>>> round(PointRotate(Point(0,5), -37), 1)
	Point(3.0, 4.0)
	"""
	radians = math.radians(angle)
	x = p.x - o.x
	y = p.y - o.y
	#y = -y
	
	x1=math.cos(radians)*x - math.sin(radians)*y
	y1=math.cos(radians)*y + math.sin(radians)*x

	#y1 = -y1
	x = x1 + o.x
	y = y1 + o.y

	return Point(x, y)
	
	
def PointAtRotatedBBox(p, w, h, angle):
	"""[x]將座標系中旋轉前的座標對應到旋轉後的座標。
	修正因為圖片旋轉而出現buffer擴大造成的座標偏移
	>>> round(PointAtRotatedBBox(Point(0,5), 10, 10, 37), 1)
	Point(3.0, 10.0)
	>>> PointAtRotatedBBox(Point(0,0),10,10,90)
	Point(0.0, 10.0)
	>>> PointAtRotatedBBox(Point(0,0),10,10,270)
	Point(10.0, 0.0)
	>>> round(PointAtRotatedBBox(Point(0,0),10,10,45), 2) == round(Point(0,1.414 * 10 / 2), 2)
	True
	"""
	
	p = PointRotate(p, -angle)
	if angle >= 0 and angle <=90:
		op = PointRotate(Point(w, 0), -angle)
		x = p.x
		y = p.y - op.y
	if angle > 90 and angle <=180:
		op = PointRotate(Point(w, 0), -angle)
		x = p.x - op.x
		op = PointRotate(Point(w, h), -angle)
		y = p.y - op.y
	if angle > 180 and angle <=270:
		op = PointRotate(Point(w, h), -angle)
		x = p.x - op.x
		op = PointRotate(Point(0, h), -angle)
		y = p.y - op.y
	if angle > 270 and angle <=360:
		op = PointRotate(Point(0, h), -angle)
		x = p.x - op.x
		y = p.y
		
	#y = -y
	#x = -x
	return round(Point(x,y),4)
	
	
def PointAtFlipedBBox(p, w, h, flipx, flipy):
	"""
	>>> PointAtFlipedBBox(Point(3,4), 10, 10, True, False)
	Point(7, 4)
	"""
	x = p.x
	y = p.y
	if flipx == True:
		x = w - p.x
	if flipy == True:
		y = h - p.y
	return Point(x,y)
		
def PointAtScaleRateBBox(p, w, h, scale_ratex, scale_ratey):
	"""
	>>> PointAtScaleRateBBox(Point(3,4), 10, 10, 2, 3)
	Point(6, 12)
	"""
	#w = scale.x * surface.get_width()
	#h = scale.y * surface.get_height()
	#scale = (w, h)
	x = p.x * scale_ratex
	y = p.y * scale_ratey
	return Point(x, y)
	
def PointAtScaleFixedBBox(p, w, h, scale_fixedx, scale_fixedy):
	"""
	>>> PointAtScaleFixedBBox(Point(3,4), 10, 10, 20, 30)
	Point(6.0, 12.0)
	"""
	scale_ratex = float(scale_fixedx) / w
	scale_ratey = float(scale_fixedy) / h
	x = p.x * scale_ratex
	y = p.y * scale_ratey
	return Point(x, y)
	
def PointAtClipedBBox(p, w, h, rect):
	"""
	>>> PointAtClipedBBox(Point(3,4), 10, 10, Rect(2,2,7,7))
	Point(1, 2)
	"""
	#w = scale.x * surface.get_width()
	#h = scale.y * surface.get_height()
	#scale = (w, h)
	x = p.x - rect.x
	y = p.y - rect.y
	return Point(x, y)
	
'''
def pointtest(tester):

	def PointDistance():
		return Distance(Point(0,0), Point(3,4)) == 5
		
	def PointRotation():
		r1 = (PointRotate(Point(3,3),90) == Point(3, -3))
		r2 = (PointRotate(Point(3,3),90, Point(3,3)) == Point(3, 3))
		return (r1 and r2)
		
	def BoundingBoxRotate():
		r1 = PointInRotatedBoundingBox(Point(0,0),10,10,90) == Point(0,10)
		r2 = PointInRotatedBoundingBox(Point(0,0),10,10,270) == Point(10,0)
		r3 = round(PointInRotatedBoundingBox(Point(0,0),10,10,45),2) == \
			 round(Point(0,1.414 * 10 / 2),2)
		return (r1 and r2 and r3)
		
	def BoundingBoxFlip():
		r1 = PointInFlipedBoundingBox(Point(3,3),10,10,True,False) == Point(7,3)
		r2 = PointInFlipedBoundingBox(Point(3,3),10,10,True,True) == Point(7,7)
		return (r1 and r2)
		
	def BoundingBoxScaleRate():
		return PointInScaleRateBoundingBox(Point(3,3),10,10,2,2) == Point(6,6)
		
	def BoundingBoxScaleFixed():
		return PointInScaleFixedBoundingBox(Point(3,3),10,10,15,15) == Point(4.5,4.5)	
	
	def BoundingBoxClip():
		return PointInClipedBoundingBox(Point(0,1),10,10,Rect(3,3,3,3)) == Point(-3,-2)
'''
	
class TransformMatrix():
	pass
	
	
if __name__ == '__main__':
	import doctest
	print(doctest.testmod())
	
